/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-10
 * V4.0
 */
package com.jphenix.clazz;

import com.jphenix.standard.docs.ClassInfo;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ListIterator;

/**
 * 属性信息类
 * @author 马宝刚
 * 2014年6月10日
 */
@ClassInfo({"2014-06-10 19:45","属性信息类"})
public class AttributeInfo {
    
    protected ConstPool constPool;      //常量池
    protected int name;                         //属性名
    protected byte[] info;                      //信息

    /**
     * 构造函数
     * @author 马宝刚
     */
    protected AttributeInfo(ConstPool cp, int attrname, byte[] attrinfo) {
        constPool = cp;
        name = attrname;
        info = attrinfo;
    }

    /**
     * 构造函数
     * @author 马宝刚
     */
    protected AttributeInfo(ConstPool cp, String attrname) {
        this(cp, attrname, null);
    }

    /**
     * 构造函数
     * @author 马宝刚
     */
    public AttributeInfo(ConstPool cp, String attrname, byte[] attrinfo) {
        this(cp, cp.addUtf8Info(attrname), attrinfo);
    }

    /**
     * 构造函数
     * @author 马宝刚
     */
    protected AttributeInfo(ConstPool cp, int n, DataInputStream in) throws IOException {
        constPool = cp;
        name = n;
        int len = in.readInt();
        info = new byte[len];
        if (len > 0) {
            in.readFully(info);
        }
    }

    /**
     * 解析属性信息
     * @param cp 常量池
     * @param in 读入流
     * @return 属性信息类
     * @throws IOException 异常
     * 2014年6月10日
     * @author 马宝刚
     */
    protected static AttributeInfo read(ConstPool cp, DataInputStream in)  throws IOException {
        int name = in.readUnsignedShort();
        String nameStr = cp.getUtf8Info(name);
        if (nameStr.charAt(0) < 'L') {
            if  (nameStr.equals(BootstrapMethodsAttribute.tag)) {
                return new BootstrapMethodsAttribute(cp, name, in);
            } else if (nameStr.equals(CodeAttribute.tag)) {
                return new CodeAttribute(cp, name, in);
            } else if (nameStr.equals(ConstantAttribute.tag)) {
                return new ConstantAttribute(cp, name, in);
            } else if (nameStr.equals(DeprecatedAttribute.tag)) {
                return new DeprecatedAttribute(cp, name, in);
            }else if (nameStr.equals(EnclosingMethodAttribute.tag)) {
                return new EnclosingMethodAttribute(cp, name, in);
            } else if (nameStr.equals(ExceptionsAttribute.tag)) {
                return new ExceptionsAttribute(cp, name, in);
            } else if (nameStr.equals(InnerClassesAttribute.tag)) {
                return new InnerClassesAttribute(cp, name, in);
            }
        } else {
            //Note that the names of Annotations attributes begin with 'R'. 
            if (nameStr.equals(LineNumberAttribute.tag)) {
                return new LineNumberAttribute(cp, name, in);
            } else if (nameStr.equals(LocalVariableAttribute.tag)) {
                return new LocalVariableAttribute(cp, name, in);
            } else if (nameStr.equals(LocalVariableTypeAttribute.tag)) {
                return new LocalVariableTypeAttribute(cp, name, in);
            } else if (nameStr.equals(AnnotationsAttribute.visibleTag)
                        || nameStr.equals(AnnotationsAttribute.invisibleTag)) {
                   return new AnnotationsAttribute(cp, name, in);
            } else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag)
                                || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag)) {
                return new ParameterAnnotationsAttribute(cp, name, in);
            } else if (nameStr.equals(SignatureAttribute.tag)) {
                return new SignatureAttribute(cp, name, in);
            } else if (nameStr.equals(SourceFileAttribute.tag)) {
                return new SourceFileAttribute(cp, name, in);
            } else if (nameStr.equals(SyntheticAttribute.tag)) {
                return new SyntheticAttribute(cp, name, in);
            } else if (nameStr.equals(StackMap.tag)) {
                return new StackMap(cp, name, in);
            } else if (nameStr.equals(StackMapTable.tag)) {
                return new StackMapTable(cp, name, in);
            }
        }
        return new AttributeInfo(cp, name, in);
    }

    /**
     * 返回属性名
     * @return
     * 2014年6月10日
     * @author 马宝刚
     */
    public String getName() {
        return constPool.getUtf8Info(name);
    }


    /**
     * 常量池
     * @return 常量池
     * 2014年6月10日
     * @author 马宝刚
     */
    public ConstPool getConstPool() {
        return constPool;
    }

    /**
     * Returns the length of this <code>attribute_info</code>
     * structure.
     * The returned value is <code>attribute_length + 6</code>.
     */
    public int length() {
        return info.length + 6;
    }

    /**
     * Returns the <code>info</code> field
     * of this <code>attribute_info</code> structure.
     *
     * <p>This method is not available if the object is an instance
     * of <code>CodeAttribute</code>.
     */
    public byte[] get() {
        return info;
    }

    protected static int getLength(ArrayList<AttributeInfo> list) {
        int size = 0;
        for (AttributeInfo attr:list) {
            size += attr.length();
        }
        return size;
    }

    protected static AttributeInfo lookup(ArrayList<AttributeInfo> list, String name) {
        if (list == null) {
            return null;
        }

        ListIterator<AttributeInfo> iterator = list.listIterator();
        while (iterator.hasNext()) {
            AttributeInfo ai = iterator.next();
            if (ai.getName().equals(name)) {
                return ai;
            }
        }

        return null;            // no such attribute
    }
}
